﻿using System;
using System.Web.WebPages;
using SilenthinkContract.Domain;
using System.Collections.Generic;
using SilenthinkCommon.Extension;
using System.Collections.Specialized;
using SilenthinkContract.Component;

namespace Web.OnlinePay
{
    public class ChinaPay : IOnlinePay
    {
        private readonly PaymentPlatform platform;

        private static string CuryId
        {
            get { return "156"; }
        }

        private static string Version
        {
            get { return "20070129"; }
        }

        private static string SuccessStatus
        {
            get { return "1001"; }
        }

        public ChinaPay(PaymentPlatform platform)
        {
            this.platform = platform;
        }

        public string CreatePayUrl(PayTrade trade)
        {
            var dic = new Dictionary<string, string>();

            const string transType = "0001";
            var orderId = trade.Id;
            var amount = GetAmount((int)(trade.Amount * 100));
            var dateTime = GetDateTime(trade.CreatedOn);
            var version =  trade.Version.TimestampToString();

            var plain = platform.MerchantId + orderId + amount + CuryId + dateTime + transType + version;

            dic.Add("MerId", platform.MerchantId);
            dic.Add("OrdId", orderId);
            dic.Add("TransAmt", amount);
            dic.Add("CuryId", CuryId);
            dic.Add("TransDate", dateTime);
            dic.Add("TransType", "1001");
            dic.Add("Version", Version);
            dic.Add("BgRetUrl", platform.NotifyUrl);
            dic.Add("PageRetUrl", platform.CallbackUrl);
            dic.Add("GateId", trade.Gateway);
            dic.Add("Priv1", version);
            
            dic.Add("ChkValue", CreateSign(plain));

            return string.Format("{0}?{1}", platform.GatewayUrl, dic.ToQueryString());
        }

        public SkResult<PayResult>NotityHandler(NameValueCollection nv)
        {
            var result = new SkResult<PayResult>();
            var merId = nv["MerId"]; //商户号
            var ordId = nv["OrderNo"]; //订单号
            var amount = nv["Amount"]; //订单金额
            var curyId = nv["CurrencyCode"]; //货币代码
            var transDate = nv["TransDate"]; //订单日期
            var transType = nv["TransType"]; //交易类型
            var status = nv["status"];
            var version = nv["Priv1"];//

            var signature = nv["checkvalue"]; //签名数据 

            result.Extra = nv;
            result.Data = new PayResult(ordId, amount.AsInt(0)/100M, string.Empty, transDate.AsDateTime(), version.StringToTimestamp(), signature);
           
            var netPay = new NetPay();
            var flag = netPay.buildKey(platform.MerchantId, 0, platform.PublicKey);
            if (flag)
            {
                flag = netPay.PublicKeyFlag && netPay.verifyTransResponse(merId, ordId, amount, curyId, transDate, transType, status, signature);
            }
            if (flag && (status == SuccessStatus))
            {
                result.Status = true;
            }
            else
            {
                result.Message = "验证签名失败";
            }
            return result;
        }

        private string CreateSign(string plain)
        {
            var netPay = new NetPay();
            var flag = netPay.buildKey(platform.MerchantId, 0, platform.PrivateKey);
            string sign = null;
            if (flag)
            {
                if (netPay.PrivateKeyFlag)
                {
                    sign = netPay.Sign(plain);
                }
            }
            return sign;
        }

        private bool VerifySign(string plain, string sign)
        {
            var netPay = new NetPay();
            var flag = netPay.buildKey(platform.MerchantId, 0, platform.PublicKey);
            if (flag)
            {
                flag = netPay.PublicKeyFlag && netPay.verifyAuthToken(plain, sign);
            }
            return flag;
        }

        private static string GetDateTime(DateTime dateTime)
        {
            return dateTime.ToString("yyyyMMdd");
        }

        private static string GetAmount(int amount)
        {
            return amount.ToString("000000000000");
        }
    }
}